home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / glibc108.zip / glibc108 / inet / res_send.c < prev    next >
C/C++ Source or Header  |  1993-05-19  |  13KB  |  479 lines

  1. /*
  2.  * ++Copyright++ 1985, 1989
  3.  * -
  4.  * Copyright (c) 1985, 1989 Regents of the University of California.
  5.  * All rights reserved.
  6.  * 
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  * 1. Redistributions of source code must retain the above copyright
  11.  *    notice, this list of conditions and the following disclaimer.
  12.  * 2. Redistributions in binary form must reproduce the above copyright
  13.  *    notice, this list of conditions and the following disclaimer in the
  14.  *    documentation and/or other materials provided with the distribution.
  15.  * 3. All advertising materials mentioning features or use of this software
  16.  *    must display the following acknowledgement:
  17.  *     This product includes software developed by the University of
  18.  *     California, Berkeley and its contributors.
  19.  * 4. Neither the name of the University nor the names of its contributors
  20.  *    may be used to endorse or promote products derived from this software
  21.  *    without specific prior written permission.
  22.  * 
  23.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  24.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  27.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  29.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  30.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  32.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  33.  * SUCH DAMAGE.
  34.  * -
  35.  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
  36.  * 
  37.  * Permission to use, copy, modify, and distribute this software for any
  38.  * purpose with or without fee is hereby granted, provided that the above
  39.  * copyright notice and this permission notice appear in all copies, and that
  40.  * the name of Digital Equipment Corporation not be used in advertising or
  41.  * publicity pertaining to distribution of the document or software without
  42.  * specific, written prior permission.
  43.  * 
  44.  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
  45.  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
  46.  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
  47.  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  48.  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  49.  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
  50.  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  51.  * SOFTWARE.
  52.  * -
  53.  * --Copyright--
  54.  */
  55.  
  56. #if defined(LIBC_SCCS) && !defined(lint)
  57. static char sccsid[] = "@(#)res_send.c    6.27 (Berkeley) 2/24/91";
  58. static char rcsid[] = "$Id: res_send.c,v 4.9.1.1 1993/05/02 22:43:03 vixie Rel $";
  59. #endif /* LIBC_SCCS and not lint */
  60.  
  61. /*
  62.  * Send query to name server and wait for reply.
  63.  */
  64.  
  65. #include <sys/param.h>
  66. #include <sys/time.h>
  67. #include <sys/socket.h>
  68. #include <sys/uio.h>
  69. #include <netinet/in.h>
  70. #include <arpa/nameser.h>
  71. #include <arpa/inet.h>
  72. #include <stdio.h>
  73. #include <errno.h>
  74. #include <resolv.h>
  75. #include "../conf/portability.h"
  76.  
  77. static int s = -1;    /* socket used for communications */
  78. static struct sockaddr no_addr;
  79.  
  80. #ifndef FD_SET
  81. #define    NFDBITS        32
  82. #define    FD_SETSIZE    32
  83. #define    FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
  84. #define    FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
  85. #define    FD_ISSET(n, p)    ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
  86. #define FD_ZERO(p)    bzero((char *)(p), sizeof(*(p)))
  87. #endif
  88.  
  89. res_send(buf, buflen, answer, anslen)
  90.     const char *buf;
  91.     int buflen;
  92.     char *answer;
  93.     int anslen;
  94. {
  95.     register int n;
  96.     int try, v_circuit, resplen, ns;
  97.     int gotsomewhere = 0, connected = 0;
  98.     int connreset = 0;
  99.     u_short id, len;
  100.     char *cp;
  101.     fd_set dsmask;
  102.     struct timeval timeout;
  103.     HEADER *hp = (HEADER *) buf;
  104.     HEADER *anhp = (HEADER *) answer;
  105.     u_int badns;        /* XXX NSMAX can't exceed #/bits per this */
  106.     struct iovec iov[2];
  107.     int terrno = ETIMEDOUT;
  108.     char junk[512];
  109.  
  110. #ifdef DEBUG
  111.     if ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY)) {
  112.         printf(";; res_send()\n");
  113.         __p_query(buf);
  114.     }
  115. #endif
  116.     if (!(_res.options & RES_INIT))
  117.         if (res_init() == -1) {
  118.             return(-1);
  119.         }
  120.     v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
  121.     id = hp->id;
  122.     badns = 0;
  123.     /*
  124.      * Send request, RETRY times, or until successful
  125.      */
  126.     for (try = 0; try < _res.retry; try++) {
  127.         for (ns = 0; ns < _res.nscount; ns++) {
  128.         if (badns & (1<<ns))
  129.             continue;
  130. #ifdef DEBUG
  131.         if (_res.options & RES_DEBUG)
  132.             printf(";; Querying server (# %d) address = %s\n",
  133.                    ns+1,
  134.                    inet_ntoa(_res.nsaddr_list[ns].sin_addr));
  135. #endif
  136.     usevc:
  137.         if (v_circuit) {
  138.             int truncated = 0;
  139.  
  140.             /*
  141.              * Use virtual circuit;
  142.              * at most one attempt per server.
  143.              */
  144.             try = _res.retry;
  145.             if (s < 0) {
  146.                 s = socket(AF_INET, SOCK_STREAM, 0);
  147.                 if (s < 0) {
  148.                     terrno = errno;
  149. #ifdef DEBUG
  150.                     if (_res.options & RES_DEBUG)
  151.                         perror("socket (vc) failed");
  152. #endif
  153.                     continue;
  154.                 }
  155.                 if (connect(s,
  156.                     (struct sockaddr *)&(_res.nsaddr_list[ns]),
  157.                     sizeof(struct sockaddr)) < 0) {
  158.                     terrno = errno;
  159. #ifdef DEBUG
  160.                     if (_res.options & RES_DEBUG)
  161.                         perror("connect failed");
  162. #endif
  163.                     (void) close(s);
  164.                     s = -1;
  165.                     continue;
  166.                 }
  167.             }
  168.             /*
  169.              * Send length & message
  170.              */
  171.             len = htons((u_short)buflen);
  172.             iov[0].iov_base = (caddr_t)&len;
  173.             iov[0].iov_len = sizeof(len);
  174.             iov[1].iov_base = (char *)buf;
  175.             iov[1].iov_len = buflen;
  176.             if (writev(s, iov, 2) != sizeof(len) + buflen) {
  177.                 terrno = errno;
  178. #ifdef DEBUG
  179.                 if (_res.options & RES_DEBUG)
  180.                     perror("write failed");
  181. #endif
  182.                 (void) close(s);
  183.                 s = -1;
  184.                 continue;
  185.             }
  186.             /*
  187.              * Receive length & response
  188.              */
  189.             cp = answer;
  190.             len = sizeof(short);
  191.             while (len != 0 &&
  192.                 (n = read(s, (char *)cp, (int)len)) > 0) {
  193.                 cp += n;
  194.                 len -= n;
  195.             }
  196.             if (n <= 0) {
  197.                 terrno = errno;
  198. #ifdef DEBUG
  199.                 if (_res.options & RES_DEBUG)
  200.                     perror("read failed");
  201. #endif
  202.                 (void) close(s);
  203.                 s = -1;
  204.                 /*
  205.                  * A long running process might get its TCP
  206.                  * connection reset if the remote server was
  207.                  * restarted.  Requery the server instead of
  208.                  * trying a new one.  When there is only one
  209.                  * server, this means that a query might work
  210.                  * instead of failing.  We only allow one reset
  211.                  * per query to prevent looping.
  212.                  */
  213.                 if (terrno == ECONNRESET && !connreset) {
  214.                     connreset = 1;
  215.                     ns--;
  216.                 }
  217.                 continue;
  218.             }
  219.             cp = answer;
  220.             if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
  221. #ifdef DEBUG
  222.                 if (_res.options & RES_DEBUG)
  223.                     fprintf(stderr,
  224.                         ";; response truncated\n");
  225. #endif
  226.                 len = anslen;
  227.                 truncated = 1;
  228.             } else
  229.                 len = resplen;
  230.             while (len != 0 &&
  231.                (n = read(s, (char *)cp, (int)len)) > 0) {
  232.                 cp += n;
  233.                 len -= n;
  234.             }
  235.             if (n <= 0) {
  236.                 terrno = errno;
  237. #ifdef DEBUG
  238.                 if (_res.options & RES_DEBUG)
  239.                     perror("read failed");
  240. #endif
  241.                 (void) close(s);
  242.                 s = -1;
  243.                 continue;
  244.             }
  245.             if (truncated) {
  246.                 /*
  247.                  * Flush rest of answer
  248.                  * so connection stays in synch.
  249.                  */
  250.                 anhp->tc = 1;
  251.                 len = resplen - anslen;
  252.                 while (len != 0) {
  253.                     n = (len > sizeof(junk) ?
  254.                         sizeof(junk) : len);
  255.                     if ((n = read(s, junk, n)) > 0)
  256.                         len -= n;
  257.                     else
  258.                         break;
  259.                 }
  260.             }
  261.         } else {
  262.             /*
  263.              * Use datagrams.
  264.              */
  265.             if (s < 0) {
  266.                 s = socket(AF_INET, SOCK_DGRAM, 0);
  267.                 if (s < 0) {
  268.                     terrno = errno;
  269. #ifdef DEBUG
  270.                     if (_res.options & RES_DEBUG)
  271.                         perror("socket (dg) failed");
  272. #endif
  273.                     continue;
  274.                 }
  275.             }
  276. #if    BSD >= 43
  277.             /*
  278.              * I'm tired of answering this question, so:
  279.              * On a 4.3BSD+ machine (client and server,
  280.              * actually), sending to a nameserver datagram
  281.              * port with no nameserver will cause an
  282.              * ICMP port unreachable message to be returned.
  283.              * If our datagram socket is "connected" to the
  284.              * server, we get an ECONNREFUSED error on the next
  285.              * socket operation, and select returns if the
  286.              * error message is received.  We can thus detect
  287.              * the absence of a nameserver without timing out.
  288.              * If we have sent queries to at least two servers,
  289.              * however, we don't want to remain connected,
  290.              * as we wish to receive answers from the first
  291.              * server to respond.
  292.              */
  293.             if (_res.nscount == 1 || (try == 0 && ns == 0)) {
  294.                 /*
  295.                  * Don't use connect if we might
  296.                  * still receive a response
  297.                  * from another server.
  298.                  */
  299.                 if (connected == 0) {
  300.                     if (connect(s,
  301.                             (struct sockaddr *)
  302.                                  &_res.nsaddr_list[ns],
  303.                             sizeof(struct sockaddr)
  304.                             ) < 0) {
  305. #ifdef DEBUG
  306.                         if (_res.options & RES_DEBUG)
  307.                             perror("connect");
  308. #endif
  309.                         continue;
  310.                     }
  311.                     connected = 1;
  312.                 }
  313.                 if (send(s, buf, buflen, 0) != buflen) {
  314. #ifdef DEBUG
  315.                     if (_res.options & RES_DEBUG)
  316.                         perror("send");
  317. #endif
  318.                     continue;
  319.                 }
  320.             } else {
  321.                 /*
  322.                  * Disconnect if we want to listen
  323.                  * for responses from more than one server.
  324.                  */
  325.                 if (connected) {
  326.                     (void) connect(s, &no_addr,
  327.                         sizeof(no_addr));
  328.                     connected = 0;
  329.                 }
  330. #endif /* BSD */
  331.                 if (sendto(s, buf, buflen, 0,
  332.                     (struct sockaddr *)&_res.nsaddr_list[ns],
  333.                     sizeof(struct sockaddr)) != buflen) {
  334. #ifdef DEBUG
  335.                     if (_res.options & RES_DEBUG)
  336.                         perror("sendto");
  337. #endif
  338.                     continue;
  339.                 }
  340. #if    BSD >= 43
  341.             }
  342. #endif
  343.  
  344.             /*
  345.              * Wait for reply
  346.              */
  347.             timeout.tv_sec = (_res.retrans << try);
  348.             if (try > 0)
  349.                 timeout.tv_sec /= _res.nscount;
  350.             if ((long) timeout.tv_sec <= 0)
  351.                 timeout.tv_sec = 1;
  352.             timeout.tv_usec = 0;
  353. wait:
  354.             FD_ZERO(&dsmask);
  355.             FD_SET(s, &dsmask);
  356.             n = select(s+1, &dsmask, (fd_set *)NULL,
  357.                 (fd_set *)NULL, &timeout);
  358.             if (n < 0) {
  359. #ifdef DEBUG
  360.                 if (_res.options & RES_DEBUG)
  361.                     perror("select");
  362. #endif
  363.                 continue;
  364.             }
  365.             if (n == 0) {
  366.                 /*
  367.                  * timeout
  368.                  */
  369. #ifdef DEBUG
  370.                 if (_res.options & RES_DEBUG)
  371.                     printf(";; timeout\n");
  372. #endif
  373. #if BSD >= 43
  374.                 gotsomewhere = 1;
  375. #endif
  376.                 continue;
  377.             }
  378.             if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
  379. #ifdef DEBUG
  380.                 if (_res.options & RES_DEBUG)
  381.                     perror("recvfrom");
  382. #endif
  383.                 continue;
  384.             }
  385.             gotsomewhere = 1;
  386.             if (id != anhp->id) {
  387.                 /*
  388.                  * response from old query, ignore it
  389.                  */
  390. #ifdef DEBUG
  391.                 if ((_res.options & RES_DEBUG) ||
  392.                     (_res.pfcode & RES_PRF_REPLY)) {
  393.                     printf(";; old answer:\n");
  394.                     __p_query(answer);
  395.                 }
  396. #endif
  397.                 goto wait;
  398.             }
  399.             if (anhp->rcode == SERVFAIL
  400.                 || anhp->rcode == NOTIMP
  401.                 || anhp->rcode == REFUSED) {
  402. #ifdef DEBUG
  403.                 if (_res.options & RES_DEBUG) {
  404.                     printf("server rejected query:\n");
  405.                     __p_query(answer);
  406.                 }
  407. #endif DEBUG
  408.                 badns |= (1<<ns);
  409.                 continue;
  410.             }
  411.             if (!(_res.options & RES_IGNTC) && anhp->tc) {
  412.                 /*
  413.                  * get rest of answer;
  414.                  * use TCP with same server.
  415.                  */
  416. #ifdef DEBUG
  417.                 if (_res.options & RES_DEBUG)
  418.                     printf(";; truncated answer\n");
  419. #endif
  420.                 (void) close(s);
  421.                 s = -1;
  422.                 v_circuit = 1;
  423.                 goto usevc;
  424.             }
  425.         }
  426. #ifdef DEBUG
  427.         if (_res.options & RES_DEBUG)
  428.             printf(";; got answer:\n");
  429.         if ((_res.options & RES_DEBUG)
  430.             || (_res.pfcode & RES_PRF_REPLY)) {
  431.             __p_query(answer);
  432.         }
  433. #endif
  434.         /*
  435.          * If using virtual circuits, we assume that the first server
  436.          * is preferred * over the rest (i.e. it is on the local
  437.          * machine) and only keep that one open.
  438.          * If we have temporarily opened a virtual circuit,
  439.          * or if we haven't been asked to keep a socket open,
  440.          * close the socket.
  441.          */
  442.         if ((v_circuit &&
  443.             ((_res.options & RES_USEVC) == 0 || ns != 0)) ||
  444.             (_res.options & RES_STAYOPEN) == 0) {
  445.             (void) close(s);
  446.             s = -1;
  447.         }
  448.         return (resplen);
  449.        }
  450.     }
  451.     if (s >= 0) {
  452.         (void) close(s);
  453.         s = -1;
  454.     }
  455.     if (v_circuit == 0)
  456.         if (gotsomewhere == 0)
  457.             errno = ECONNREFUSED;    /* no nameservers found */
  458.         else
  459.             errno = ETIMEDOUT;    /* no answer obtained */
  460.     else
  461.         errno = terrno;
  462.     return (-1);
  463. }
  464.  
  465. /*
  466.  * This routine is for closing the socket if a virtual circuit is used and
  467.  * the program wants to close it.  This provides support for endhostent()
  468.  * which expects to close the socket.
  469.  *
  470.  * This routine is not expected to be user visible.
  471.  */
  472. _res_close()
  473. {
  474.     if (s != -1) {
  475.         (void) close(s);
  476.         s = -1;
  477.     }
  478. }
  479.